#undef CB_PRECOMP

#ifdef CB_PRECOMP
    #include "sdk_precomp.h"
#endif

#ifndef CB_PRECOMP
    #include <wx/filename.h>
    #include <wx/notebook.h>
    #include <wx/menu.h>
    #include <wx/wfstream.h>

    #include "manager.h"
    #include "seditorbase.h"
    #include "scbeditor.h"
    #include "seditormanager.h"
    #include "pluginmanager.h"
    #include "cbproject.h"
#endif

#include <wx/xrc/xmlres.h>

#include "prep.h"
#include "scbeditor.h"
#include "seditorbase.h"
#include "seditormanager.h"
#include "cbstyledtextctrl.h"
#include "cbauibook.h"
#include "snippetsconfig.h"

int idEditHighlightMode = XRCID("idEditHighlightMode");
int idEditHighlightModeText = XRCID("idEditHighlightModeText");


int editorbase_RegisterId(int id) {
    wxRegisterId(id);
    return id;
}

// ----------------------------------------------------------------------------
struct EditorBaseInternalData
{
	EditorBaseInternalData(SEditorBase* owner)
		: m_pOwner(owner),
		m_DisplayingPopupMenu(false),
		m_CloseMe(false)
	{}

	SEditorBase* m_pOwner;
	bool m_DisplayingPopupMenu;
	bool m_CloseMe;
};

const int EditorMaxSwitchTo = 255;
const int idSwitchFile1 = wxNewId();
const int idSwitchFileMax = editorbase_RegisterId(idSwitchFile1 + EditorMaxSwitchTo -1);

const int idCloseMe = wxNewId();
const int idCloseAll = wxNewId();
const int idCloseAllOthers = wxNewId();
const int idSaveMe = wxNewId();
const int idSaveAll = wxNewId();
const int idSwitchTo = wxNewId();
const int idGoogle = wxNewId();
const int idGoogleCode = wxNewId();
const int idMsdn = wxNewId();

BEGIN_EVENT_TABLE(SEditorBase, wxPanel)
    EVT_MENU_RANGE(idSwitchFile1, idSwitchFileMax,SEditorBase::OnContextMenuEntry)
    EVT_MENU(idCloseMe, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idCloseAll, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idCloseAllOthers, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idSaveMe, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idSaveAll, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idGoogle, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idGoogleCode, SEditorBase::OnContextMenuEntry)
    EVT_MENU(idMsdn, SEditorBase::OnContextMenuEntry)
END_EVENT_TABLE()

void SEditorBase::InitFilename(const wxString& filename) {
    if (filename.IsEmpty())
        m_Filename = realpath(CreateUniqueFilename());
    else
        m_Filename = realpath(filename);

    wxFileName fname;
    fname.Assign(m_Filename);
    m_Shortname = fname.GetFullName();
   
}

// ----------------------------------------------------------------------------
wxString SEditorBase::CreateUniqueFilename() {
    const wxString prefix = _("Untitled");
    const wxString path = wxGetCwd() + wxFILE_SEP_PATH;
    wxString tmp;
    int iter = 0;
    while (true)
    {
        tmp.Clear();
        tmp << path << prefix << wxString::Format(_T("%d"), iter);
        if (! GetEditorManager()->GetEditor(tmp) &&
                !wxFileExists(path + tmp))
        {
            return tmp;
        }
        ++iter;
    }
}

// ----------------------------------------------------------------------------
SEditorBase::SEditorBase(wxWindow* parent, const wxString& filename)
// ----------------------------------------------------------------------------
        : wxPanel(parent, -1),
        m_IsBuiltinEditor(false),
        m_Shortname(_T("")),
        m_Filename(_T("")),
        m_WinTitle(filename) {
   
    m_pParent = parent;
	m_pData = new EditorBaseInternalData(this);
   
    m_pEditorManager = GetConfig()->GetEditorManager(::wxGetTopLevelParent(this));
    GetEditorManager()->AddCustomEditor(this);
    InitFilename(filename);
    SetTitle(m_Shortname);
}

// ----------------------------------------------------------------------------
SEditorBase::~SEditorBase() {
   
    if (GetEditorManager() )
        GetEditorManager()->RemoveCustomEditor(this);

    if (Manager::Get()->GetPluginManager())
    {
        CodeBlocksEvent event(cbEVT_EDITOR_CLOSE);
        event.SetEditor((EditorBase*)this);
        event.SetString(m_Filename);

       
       
    }

    delete m_pData;
}

const wxString& SEditorBase::GetTitle() {
    return m_WinTitle;
}

void SEditorBase::SetTitle(const wxString& newTitle) {
    m_WinTitle = newTitle;
    int mypage = GetEditorManager()->FindPageFromEditor(this);
    if (mypage != -1)
        GetEditorManager()->GetNotebook()->SetPageText(mypage, newTitle);
}

void SEditorBase::Activate() {
    GetEditorManager()->SetActiveEditor(this);
}

bool SEditorBase::Close() {
    Destroy();
    return true;
}

bool SEditorBase::IsBuiltinEditor() const {
    return m_IsBuiltinEditor;
}

bool SEditorBase::ThereAreOthers() const {
    bool hasOthers = false;
    hasOthers = GetEditorManager()->GetEditorsCount() > 1;
   
   
   
   
   
   
   
   
    return hasOthers;
}

wxMenu* SEditorBase::CreateContextSubMenu(int id) {
    wxMenu* menu = 0;

    if(id == idSwitchTo)
    {
        menu = new wxMenu;
        m_SwitchTo.clear();
        for (int i = 0; i < EditorMaxSwitchTo && i < GetEditorManager()->GetEditorsCount(); ++i)
        {
            SEditorBase* other = GetEditorManager()->GetEditor(i);
            if (!other || other == this)
                continue;
            int id = idSwitchFile1+i;
           
            m_SwitchTo[id] = (SEditorBase*)other;
            menu->Append(id, other->GetShortName());
        }
        if(!menu->GetMenuItemCount())
        {
            delete menu;
            menu = 0;
        }
    }
    return menu;
}

void SEditorBase::BasicAddToContextMenu(wxMenu* popup,ModuleType type)  
{
    bool noeditor = (type != mtEditorManager);                         
    if (type == mtOpenFilesList)                                       
    {
      popup->Append(idCloseMe, _("Close"));
      popup->Append(idCloseAll, _("Close all"));
      popup->Append(idCloseAllOthers, _("Close all others"));
      popup->AppendSeparator();
      popup->Append(idSaveMe, _("Save"));
      popup->Append(idSaveAll, _("Save all"));
      popup->AppendSeparator();
     
      popup->Enable(idSaveMe, GetModified());

      bool hasOthers = ThereAreOthers();
      popup->Enable(idCloseAll, hasOthers);
      popup->Enable(idCloseAllOthers, hasOthers);
    }
    if(!noeditor)
    {
        wxMenu* switchto = CreateContextSubMenu(idSwitchTo);
        if(switchto)
            popup->Append(idSwitchTo, _("Switch to"), switchto);
    }
}

void SEditorBase::DisplayContextMenu(const wxPoint& position, ModuleType type)  
{
    bool noeditor = (type != mtEditorManager);                                 
   
   
   

   
    if (!OnBeforeBuildContextMenu(position, type))             
        return;

    wxMenu* popup = new wxMenu;

    if(!noeditor && wxGetKeyState(WXK_CONTROL))
    {
        cbStyledTextCtrl* control = GetEditorManager()->GetBuiltinActiveEditor()->GetControl();
        wxString text = control->GetSelectedText();
        if (text.IsEmpty())
        {
            const int pos = control->GetCurrentPos();
            text = control->GetTextRange(control->WordStartPosition(pos, true), control->WordEndPosition(pos, true));
        }

        popup->Append(idGoogle, _("Search the Internet for \"") + text + _("\""));
        popup->Append(idMsdn, _("Search MSDN for \"") + text + _("\""));
        popup->Append(idGoogleCode, _("Search Google Code for \"") + text + _("\""));

        lastWord = text;

        wxMenu* switchto = CreateContextSubMenu(idSwitchTo);
        if(switchto)
        {
            popup->AppendSeparator();
            popup->Append(idSwitchTo, _("Switch to"), switchto);
        }
    }
    else if(!noeditor && wxGetKeyState(WXK_ALT))
    {
    }
    else
    {
       
        BasicAddToContextMenu(popup, type);        

       
        AddToContextMenu(popup, type, false);      

       
        FileTreeData* ftd = new FileTreeData(0, FileTreeData::ftdkUndefined);
        ftd->SetFolder(m_Filename);
        Manager::Get()->GetPluginManager()->AskPluginsForModuleMenu(type, popup, ftd);             
        delete ftd;

        popup->AppendSeparator();
       
        AddToContextMenu(popup, type, true);           
    }
   
    OnAfterBuildContextMenu(type);             

   
    wxPoint clientpos;
    if (position==wxDefaultPosition)
    {
       
       
        cbStyledTextCtrl* const control = GetEditorManager()->GetBuiltinActiveEditor()->GetControl();
        clientpos = control->PointFromPosition(control->GetCurrentPos());
    }
    else
    {
        clientpos = ScreenToClient(position);
    }

	m_pData->m_DisplayingPopupMenu = true;
    PopupMenu(popup, clientpos);
    delete popup;
    m_pData->m_DisplayingPopupMenu = false;

   
   
    if (m_pData->m_CloseMe)
		GetEditorManager()->Close(this);
}

void SEditorBase::OnContextMenuEntry(wxCommandEvent& event) {
   
   
   

    const int id = event.GetId();
    m_pData->m_CloseMe = false;

    if (id == idCloseMe)
    {
    	if (m_pData->m_DisplayingPopupMenu)
			m_pData->m_CloseMe = true;
		else
			GetEditorManager()->Close(this);
    }
    else if (id == idCloseAll)
    {
    	if (m_pData->m_DisplayingPopupMenu)
    	{
			GetEditorManager()->CloseAllExcept(this);
			m_pData->m_CloseMe = true;
    	}
		else
			GetEditorManager()->CloseAll();
    }
    else if (id == idCloseAllOthers)
    {
        GetEditorManager()->CloseAllExcept(this);
    }
    else if (id == idSaveMe)
    {
        Save();
    }
    else if (id == idSaveAll)
    {
        GetEditorManager()->SaveAll();
    }
    else
    if (id >= idSwitchFile1 && id <= idSwitchFileMax)
    {
       
        SEditorBase *const ed = (SEditorBase*)m_SwitchTo[id];
        if (ed)
        {
            GetEditorManager()->SetActiveEditor(ed);
        }
        m_SwitchTo.clear();
    }
    else
    {
        if (id == idGoogleCode)
        {
            wxLaunchDefaultBrowser(wxString(_T("http://www.google.com/codesearch?q=")) << URLEncode(lastWord));
        }
        else if (id == idGoogle)
        {
            wxLaunchDefaultBrowser(wxString(_T("http://www.google.com/search?q=")) << URLEncode(lastWord));
        }
        else if (id == idMsdn)
        {
            wxLaunchDefaultBrowser(wxString(_T("http://search.microsoft.com/search/results.aspx?qu=")) << URLEncode(lastWord) << _T("&View=msdn"));
        }
    }
}

void SEditorBase::SearchGotoLine() {
    ScbEditor* ed = GetEditorManager()->GetBuiltinActiveEditor();
    if (!ed)
        return;

    int max = ed->GetControl()->LineFromPosition(ed->GetControl()->GetLength()) + 1;

    
    wxString strLine = cbGetTextFromUser( wxString::Format(_("Line (1 - %d): "), max),
                                        _("Goto line"),
                                        _T( "" ),
                                        this );
    long int line = 0;
    strLine.ToLong(&line);
    if ( line >= 1 && line <= max )
    {
        ed->UnfoldBlockFromLine(line - 1);
        ed->GotoLine(line - 1);
    }
}

void SEditorBase::SearchFind() {
    bool bDoMultipleFiles ;
    bDoMultipleFiles = ! GetEditorManager()->GetBuiltinActiveEditor();
    GetEditorManager()->ShowFindDialog(false, bDoMultipleFiles);

}

void SEditorBase::SearchFindNext(bool next) {
    GetEditorManager()->FindNext(next);

}

void SEditorBase::OnSearchReplace() {
    bool bDoMultipleFiles = false;
    if(!bDoMultipleFiles)
    {
        bDoMultipleFiles = ! GetEditorManager()->GetBuiltinActiveEditor();
    }
    GetEditorManager()->ShowFindDialog(true, bDoMultipleFiles);

}
